/*
 * TowerRedTwo.java
 *
 * Created on December 19, 2007, 8:43 PM
 *
 * Copyright (C) 2007-2008  Hylke van der Schaaf
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, in version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
package hextd.tower;

import hextd.hex.Hex;
import hextd.creep.Creep;
import hextd.util.Cache;
import hextd.core.Context;
import hextd.util.Geometry;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

/**
 *
 * @author hylke
 */
public class TowerRedTwo extends TowerBase {

	public static int price = 20000;
	public static int damage = 20000;
	public static float range = 6f;
	public static float spreadRadiusBase = 2f;
	public static float projectileSpeedBase = 0.4f;
	private Creep fireAt = null;
	private Creep.COLOR damageColor = Creep.COLOR.RED;
	private int coolDown = 0;
	private int coolDownTime = 14;
	private Color transColor;
	private float projectileSpeed;
	private float spreadRadius;
	private float spreadRadius2;
	private ArrayList<Projectile> projectiles;
	private BufferedImage[] projectileImg;

	/** Creates a new instance of TowerRedTwo */
	public TowerRedTwo(Context context, Hex hex, int owner, int activateTick) {
		super(TowerFactory.type.redTwo, price, damage, range, owner, activateTick);
		this.lineColor = Color.RED;
		this.transColor = new Color(this.lineColor.getRed(), this.lineColor.getGreen(), this.lineColor.getBlue(), 50);
		this.doInit(context, hex);
		this.projectiles = new ArrayList<Projectile>();
	}

	@Override
	public void runTick(int gameTime) {
		if (this.coolDown > 0) {
			this.coolDown--;
		} else {
			if (!this.lock) {
				this.fireAt = null;
			}
			Creep enemy = this.findEnemy(this.fireAt, false);
			this.fireAt = enemy;

			if (enemy != null) {
				Projectile p = new Projectile();
				p.target = enemy;
				p.x = this.xFloat;
				p.y = this.yFloat;
				this.projectiles.add(p);
				this.coolDown = this.coolDownTime;
			}
		}

		for (int ip = this.projectiles.size() - 1; ip >= 0; ip--) {
			Projectile p = this.projectiles.get(ip);
			float dx, dy, r, factor;
			if (p.status == 0) {
				dx = p.target.getX() - p.x;
				dy = p.target.getY() - p.y;
				r = (float) Math.sqrt(dx * dx + dy * dy);
				factor = this.projectileSpeed / r;
				if (factor < 1) {
					dx *= factor;
					dy *= factor;
					p.x += dx;
					p.y += dy;
				} else {
					// HIT!
					p.x = p.target.getX();
					p.y = p.target.getY();
					p.status = 1;
				}
			}
			if (p.status == 1) {
				p.targetsHit = this.findEnemiesInRange(p.x, p.y, this.spreadRadius);
				long damageBlast;
				double rs;
				Creep enemy;
				for (int i = 0; i < p.targetsHit.length; i++) {
					enemy = p.targetsHit[i];
					dx = p.x - enemy.getX();
					dy = p.y - enemy.getY();
					rs = (float) Math.sqrt(dx * dx + dy * dy);
					damageBlast = Math.round(this.damageCurrent * (1 - rs / this.spreadRadius));
					enemy.doDamage(this.getOwner(), damageBlast, this.damageColor);
				}
				p.status++;
			} else if (p.status > 1) {
				p.target = null;
				this.projectiles.remove(ip);
			}
		}
	}

	@Override
	public String getStatusString() {
		String retString = "";
		retString += "<h1>Red Tower 2</h1>" +
				"<p>" +
				"<b>Level:</b> " + (1 + this.level) + "<br>\n" +
				"<b>Damage:</b> " + this.damageText + "<br>\n" +
				"<b>Range:</b> " + this.rangeText + "<br>" +
				"</p>\n";
		return retString;
	}

	@Override
	public String getInfoString() {
		String retString = "";
		retString += "<h1>Red Tower 2</h1>" +
				"<p>" +
				"Tower firing fast homing projectiles with a small splash radius. " +
				"When the projectiles lose their target they continue to the last known location and detonate." +
				"<br>Strong against red enemies, very weak against green enemies." +
				"</p>" +
				"<p>" +
				"<b>Price:</b> " + TowerRedTwo.form.format(TowerRedTwo.price) + "<br>" +
				"<b>Damage:</b> " + TowerRedTwo.form.format(this.damageCurrent) + " + splash<br>" +
				"<b>Range:</b> " + TowerRedTwo.form.format(rangeCurrent) + "<br>" +
				"<b>Refire rate:</b> 1.25/s" +
				"</p>";
		return retString;
	}

	@Override
	protected void calcDamageRange() {
		super.calcDamageRange();
		this.spreadRadius = TowerRedTwo.spreadRadiusBase;
		this.spreadRadius2 = this.spreadRadius * this.spreadRadius;
		this.projectileSpeed = projectileSpeedBase;
	}

	@Override
	protected void generateShapes() {
		Cache cache = this.cn.getCache();

		float width = hexPaintWidth;
		int shapeCount = 5;
		this.shapes = new Shape[shapeCount];
		this.shapes[0] = new Ellipse2D.Float(-0.3f * this.paintScale, -0.3f * this.paintScale, 0.6f * this.paintScale, 0.6f * this.paintScale);
		this.shapes[1] = new Ellipse2D.Float(-0.3f * this.paintScale, -0.3f * this.paintScale, 0.6f * this.paintScale, 0.6f * this.paintScale);
		this.shapes[2] = new Ellipse2D.Float(-1.0f * strokeScale, -1.0f * strokeScale, 2.0f * strokeScale, 2.0f * strokeScale);
		this.shapes[3] = new Line2D.Float(width, 0.5f * this.paintScale, 0.3f * width, 0.15f * this.paintScale);
		this.shapes[4] = new Line2D.Float(-width, -0.5f * this.paintScale, -0.3f * width, -0.15f * this.paintScale);

		this.shapeAction = new int[shapeCount];
		this.shapeAction[0] = 2;
		this.shapeAction[1] = 1;
		this.shapeAction[2] = 1;
		this.shapeAction[3] = 1;
		this.shapeAction[4] = 1;

		this.shapeColor = new Color[shapeCount];
		this.shapeColor[0] = this.transColor;
		this.shapeColor[1] = this.lineColor;
		this.shapeColor[2] = this.lineColor;
		this.shapeColor[3] = this.lineColor;
		this.shapeColor[4] = this.lineColor;

		this.strokes = new Stroke[shapeCount];
		this.strokes[0] = new BasicStroke(2.0f * strokeScale, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL);
		this.strokes[1] = this.strokes[0];
		this.strokes[2] = this.strokes[0];
		this.strokes[3] = this.strokes[0];
		this.strokes[4] = this.strokes[0];

		if (cache.hasBufImgArr("Red2ProjImagArr")) {
			this.projectileImg = cache.getBufImgArr("Red2ProjImagArr");
		} else {
			float pWidth = width / 10f;
			float pScale = this.paintScale / 10f;
			int imgW = (int) (pScale * 2) + 2;
			int imgH = (int) (pScale * 2) + 2;
			this.projectileImg = new BufferedImage[3];
			float[][] pPoints = Geometry.createHexCoords(pScale, (float) imgW / 2, (float) imgH / 2);
			AffineTransform atr = new AffineTransform();
			for (int i = 0; i < this.projectileImg.length; i++) {
				atr.setToIdentity();
				atr.rotate(Math.PI * i * 2 / 6 / 3, (float) imgW / 2, (float) imgH / 2);

				this.projectileImg[i] = new BufferedImage(imgW, imgH, BufferedImage.TYPE_INT_ARGB_PRE);
				//GeneralPath polyHex = Geometry.coordsToGeneralPath(pPoints, true);
				Graphics2D g2 = this.projectileImg[i].createGraphics();
				g2.transform(atr);
				g2.setColor(this.lineColor);
				//g2.draw(polyHex);
				g2.draw(new Line2D.Float(pPoints[0][0], pPoints[0][1], pPoints[3][0], pPoints[3][1]));
				g2.draw(new Line2D.Float(pPoints[1][0], pPoints[1][1], pPoints[4][0], pPoints[4][1]));
				g2.draw(new Line2D.Float(pPoints[2][0], pPoints[2][1], pPoints[5][0], pPoints[5][1]));
				g2.dispose();
			}
			cache.putBufImgArr("Red2ProjImagArr", this.projectileImg);
		}

	}

	@Override
	public void paintEffects(Graphics2D g2, int gameTime) {
		Stroke defaultStroke = g2.getStroke();

		g2.setColor(this.lineColor);

		float pw = (float) this.projectileImg[0].getWidth() / 2f;
		float ph = (float) this.projectileImg[0].getHeight() / 2f;
		for (int ip = 0; ip < this.projectiles.size(); ip++) {
			Projectile p = this.projectiles.get(ip);
			if (p.status == 0) {
				g2.drawImage(
						this.projectileImg[p.anim],
						Math.round(p.x * paintScale + offsetX - pw),
						Math.round(p.y * paintScale + offsetY - ph),
						null);
				p.anim++;
				if (p.anim >= this.projectileImg.length) {
					p.anim = 0;
				}
			} else {
				synchronized (p) {
					if (p.targetsHit != null) {
						for (int i = 0; i < p.targetsHit.length; i++) {
							g2.draw(new Line2D.Float(
									p.x * paintScale + offsetX,
									p.y * paintScale + offsetY,
									p.targetsHit[i].getPaintX(),
									p.targetsHit[i].getPaintY()));
						}
					}
				}
			}
		}

		g2.setStroke(defaultStroke);
	}
}
